//-----------------------------------------------------------------------------
//  File          : sysutil.c
//  Module        :
//  Description   : Include Enhance utitilies function.
//  Author        : Lewis
//  Notes         : No UI is include in the routines, call util lib
//                  Only.
//
// ============================================================================
// | Naming conventions                                                       |
// | ~~~~~~~~~~~~~~~~~~                                                       |
// |         Struct/Array : Leading s                                         |
// |             Constant : Leading K                                         |
// |      Global Variable : Leading g  (variable use outside one C file)      |
// |                                                                          |
// |   BYTE( 8 Bits) size : Leading b                                         |
// |   CHAR( 8 Bits) size : Leading c                                         |
// |   WORD(16 Bits) size : Leading w                                         |
// |  DWORD(32 Bits) size : Leading d                                         |
// |    int(32 Bits) size : Leading i                                         |
// | DDWORD(64 Bits) size : Leading dd                                        |
// |              Pointer : Leading p                                         |
// |                                                                          |
// |    Function argument : Leading a                                         |
// |       Local Variable : All lower case                                    |
// |                                                                          |
// | Examples:                                                                |
// |                Array : Leading s, (sb = arrary of byte, etc)             |
// |              Pointer : Leading p, (pb = pointer of byte, etc)            |
// ============================================================================
//
//  Date          Who         Action
//  ------------  ----------- -------------------------------------------------
//  01 Feb  2010  Lewis       Initial Version.
//-----------------------------------------------------------------------------
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include "system.h"

//-----------------------------------------------------------------------------
//    Defines
//-----------------------------------------------------------------------------
// Disp Commands
#define SU_DELEOL              0x05
#define SU_PUSHCURSOR          0x0D
#define SU_POPCURSOR           0x0E
#define SU_SELSMFONT           0x10
#define SU_SELBIGFONT          0x11
#define SU_SELSPFONT           0x12
#define SU_ESC                 0x1B

#define LINE_CTRL(x)           (x&0x0F)
#define LINE_FONT(x)           (x&0xF000)
#define FONT_IDX(x)            (x>>12)

//-----------------------------------
// SU_SMFONT  => LCD=8x16
// SU_BIGFONT => LCD=4x16
// SU_SPFONT  => LCD=8x21
#define SU_SMFONT               0x0000
#define SU_BIGFONT              0x1000
#define SU_SPFONT               0x2000
#define SU_SPCHI                0x3000
#define SU_8X16FONT             0x4000
#define SU_8X8FONT              0x5000
#define SU_6X8FONT              0x6000
#define SU_8X16TFONT            0x7000
#define MAX_SU_FONT             0x08

// Control
#define SU_LEFT                  0x00
#define SU_RIGHT                 0x01
#define SU_CENTER                0x02

// Option
#define SU_REVERSE               0x10
#define SU_CLREOL                0x20
#define SU_CLRDISP               0x80

#define SU_CLRHOME           K_ClrHome
#define SU_REV_ON            K_RevOn
#define SU_REV_OFF           K_RevOff
#define SU_SAVE_CFG          K_PushCursor
#define SU_LOAD_CFG          K_PopCursor
#define DispCtrl(x)          os_disp_putc(x)

#if (PR608D|R700|TIRO|PR608)
#define SU_WIDTH_DOT             (128)
#define SU_HEIGHT_DOT            (64)
#define SU_NOR_LINESIZE          (16)
#define SU_MAX_LINESIZE          (21)
// Line number defines
#define SU_LINE1                 0x0000
#define SU_LINE2                 0x0200
#define SU_LINE3                 0x0400
#define SU_LINE4                 0x0600
#define SU_LINE5                 0x0800
#define SU_LINE6                 0x0A00
#define SU_LINE7                 0x0C00
#define SU_LINE8                 0x0E00
#define SU_LINE9                 0x0000
#define SU_MAX_LINE              SU_LINE8
// func
#define LINE_NO(x)             ((x>>4)&0xE0)
#define LINE_POS(x)            (x&0x001F)
#elif (T800)
#define SU_WIDTH_DOT             (320)
#define SU_HEIGHT_DOT            (216)
#define SU_NOR_LINESIZE          (20)
#define SU_MAX_LINESIZE          (26)
// Line number defines
#define SU_LINE1                 0x0100
#define SU_LINE2                 0x0200
#define SU_LINE3                 0x0300
#define SU_LINE4                 0x0400
#define SU_LINE5                 0x0500
#define SU_LINE6                 0x0600
#define SU_LINE7                 0x0700
#define SU_LINE8                 0x0800
#define SU_LINE9                 0x0900
#define SU_MAX_LINE              SU_LINE9
// func
#define LINE_NO(x)             ((x>>8)&0x0F)
#define LINE_POS(x)            ((x&0x00FF)+1)
#endif


//-----------------------------------------------------------------------------
//    Constant
//-----------------------------------------------------------------------------
#if (T800)
const BYTE KLineSize[] = { 20, 20, 26, 20,
                           20, 20, 26, 20
                         };
#else
const BYTE KLineSize[] = { 16, 16, 21, 16,
                           16, 16, 21, 16
                         };
#endif
#if (PR608D|R700)
const BYTE KFontCode[] = { K_SelSmFont,   K_SelBigFont, K_SelSpFont,  K_SelSpChnFont,
                           K_SelUser8x16, K_SelUser8x8, K_SelUser6x8, K_SelUser8x16T
                         };
#elif (T800|TIRO|PR608)
const BYTE KFontCode[] = { K_SelSmFont,   K_SelBigFont, K_SelSpFont,  K_SelBigFont,
                           K_SelUser8x16, K_SelUser8x8, K_SelUser6x8, K_SelUser8x16T
                         };
#endif

//*****************************************************************************
//  Function        : mwClearLine
//  Description     : Clear the specify line.
//  Input           : aLineNo;  // line number of the line to be clear
//  Return          : TRUE/FALSE;
//  Note            : N/A
//  Globals Changed : N/A
//*****************************************************************************
DWORD mwClearLine(DWORD aLineNo, DWORD aReverse)
{
  BYTE tmpbuf[64], *ptr;

  ptr = tmpbuf;

  if (aReverse)  *ptr++ = SU_REV_ON;
  *ptr++ = SU_ESC;
#if (T800)
  *ptr++ = LINE_NO(aLineNo);
  *ptr++ = (LINE_POS(aLineNo)==0x00)?0x01:LINE_POS(aLineNo);
#elif (PR608D|R700|TIRO|PR608)
  *ptr++ =(BYTE)(LINE_NO(aLineNo)|LINE_POS(aLineNo));
#endif
  *ptr++ = SU_DELEOL;
  if (aReverse)  *ptr++ = SU_REV_OFF;
  os_disp_putn(tmpbuf, ptr-tmpbuf);
  return TRUE;
}
//*****************************************************************************
//  Function        : mwClrBelow
//  Description     : Clear the lines below selection.
//  Input           : aLineNo;
//  Return          : TRUE/FALSE;
//  Note            : N/A
//  Globals Changed : N/A
//*****************************************************************************
DWORD mwClrBelow(DWORD aLineNo)
{
  DWORD line_tmp = SU_MAX_LINE;

  os_disp_putc(SU_PUSHCURSOR);
  os_disp_putc(SU_SELSMFONT);
  do {
    mwClearLine(line_tmp, FALSE);
    if (line_tmp <= aLineNo)
      break;
    line_tmp -= (SU_LINE3-SU_LINE2);
  } while (1);
  os_disp_putc(SU_POPCURSOR);
  return TRUE;
}
//*****************************************************************************
//  Function        : mwDispGotoXY
//  Description     : Set Cursor Position.
//  Input           : aOffset;      // LINE + LINE OFFSET
//                    aFont;        // FONT IDX
//  Return          : N/A
//  Note            : N/A
//  Globals Changed : N/A
//*****************************************************************************
DWORD mwDispGotoXY(DWORD aOffset, DWORD aFont)
{
  BYTE tmp[4];

  tmp[0] = KFontCode[FONT_IDX(aFont)];
  tmp[1] = SU_ESC;
#if (T800)
  tmp[2] = LINE_NO(aOffset) == 0 ? 1: LINE_NO(aOffset);
  tmp[3] = LINE_POS(aOffset) == 0 ? 1 : LINE_POS(aOffset);
  os_disp_putn(tmp, 4);
#elif (PR608D|R700|TIRO|PR608)
  tmp[2] = (LINE_NO(aOffset)|LINE_POS(aOffset));
  os_disp_putn(tmp, 3);
#endif
  return TRUE;
}
//*****************************************************************************
//  Function        : mwDispLine
//  Description     : Display Line Data
//  Input           : aMsg;         // pointer to message string
//                    aOffset;      // line no + line offset
//                    aCtrl;        // Control + font
//  Return          : TRUE/FALSE;
//  Note            : N/A
//  Globals Changed : N/A
//*****************************************************************************
DWORD mwDispLine(const void *aMsg, DWORD aOffset, DWORD aCtrl)
{
  DWORD disp_len, line_size;
  BYTE  disp_buf[SU_MAX_LINESIZE+3], *ptr;

  line_size = KLineSize[FONT_IDX(aCtrl)<MAX_SU_FONT?FONT_IDX(aCtrl):MAX_SU_FONT-1];
  memset(disp_buf, ' ', sizeof(disp_buf));
  disp_len = strlen(aMsg);
  disp_len = disp_len > line_size ? line_size : disp_len;
  ptr = disp_buf;
  if (aCtrl&SU_REVERSE) {
    *ptr++ = SU_REV_ON;
  }
  switch (LINE_CTRL(aCtrl)) {
    case SU_CENTER:
      memcpy((ptr+(line_size-disp_len)/2), aMsg, disp_len);
      disp_len = KLineSize[FONT_IDX(aCtrl)];
      ptr += disp_len;
      break;
    case SU_RIGHT:
      aOffset |= (line_size-disp_len);
      memcpy(ptr, aMsg, disp_len);
      ptr += disp_len;
      break;
    case SU_LEFT:
    default:
      memcpy(ptr, aMsg, disp_len);
      ptr += disp_len;
  }
  if (aCtrl&SU_REVERSE) {
    *ptr++ = SU_REV_OFF;
  }
  if (aCtrl&SU_CLRDISP) {
    DispCtrl(SU_CLRHOME);
  }

  if (aCtrl&SU_CLREOL) {
    mwClearLine(aOffset, (aCtrl&SU_REVERSE));
  }
//  else if ((LINE_CTRL(aCtrl)==SU_CENTER) && (LINE_FONT(aCtrl)==SU_SPFONT)) {
//    mwClearLine(aOffset, (aCtrl&SU_REVERSE));
//  }

  mwDispGotoXY(aOffset, aCtrl);
  os_disp_putn(disp_buf, (ptr-disp_buf));
  return TRUE;
}

